package com.sky.service.impl;

import com.sky.dto.GoodsSalesDTO;
import com.sky.entity.Orders;
import com.sky.mapper.OrdersMapper;
import com.sky.mapper.UserMapper;
import com.sky.service.ReportService;
import com.sky.vo.OrderReportVO;
import com.sky.vo.SalesTop10ReportVO;
import com.sky.vo.TurnoverReportVO;
import com.sky.vo.UserReportVO;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.LongStream;

@Service
public class ReportServiceIImpl implements ReportService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private OrdersMapper ordersMapper;

    /**
     * 营业额统计
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {
        //1、根据起始日期，得到区间内的所有日期
        List<LocalDate> dateList = getDateList(begin, end);
        //分组统计营业额
        Map param = new HashMap();
        param.put("beginDate", begin);
        param.put("endDate", end);
        param.put("status", Orders.COMPLETED);
        //分组查询
        List<Map> turnoverMapList = ordersMapper.groupSumAmountByParams(param);
        Map<String, BigDecimal> turnoverMap = turnoverMapList.stream()
                .collect(Collectors.toMap(m -> (String) m.get("date"), m -> (BigDecimal) m.get("amount")));
        List<BigDecimal> turnoverList = new ArrayList<>();
        for (LocalDate date : dateList) {
            BigDecimal amount = turnoverMap.get(date.toString());
            amount = ObjectUtils.isEmpty(amount) ? BigDecimal.valueOf(0.0) : amount;
            turnoverList.add(amount);
        }
        //将list转成逗号拼接的字符串
        String join = StringUtils.join(dateList, ",");
        join = dateList.stream().map(date -> date.toString()).collect(Collectors.joining(","));
        //组装TurnoverReportVO并返回
        String joi = StringUtils.join(turnoverList, ",");
        return TurnoverReportVO.builder().dateList(join).turnoverList(joi).build();
    }

    /**
     * 用户数据统计
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public UserReportVO userStatistics(LocalDate begin, LocalDate end) {
        //1、根据起始日期，得到区间内的所有日期
        List<LocalDate> dateList = getDateList(begin, end);
        //2,分组统计用户数据
        //2.1创建HashMap容器
        Map params = new HashMap();
        //2.2添加开始日期
        params.put("beginDate", begin);
        //2.3添加结束日期
        params.put("endDate", end);
        //2.4把从数据库查到的数据封装的List合集中
        List<Map> userMap = userMapper.groupCountUserByParams(params);
        //2.5分组查询每日新增用户数
        Map<String, Long> collect = userMap.stream().collect(Collectors.toMap(u -> (String) u.get("date"), u -> (Long) u.get("num")));
        //2.6查询截止到开始日期之前的用户总数
        params.put("date", begin.minusDays(1));
        params.put("newUserFalse", false);

        Integer integer = userMapper.countUserByParams(params);
        //新增用户数
        List<Integer> totalUserList = new ArrayList<>();
        //新增用户数
        List<Long> newUserList = new ArrayList<>();
        for (LocalDate date : dateList) {
            //2.7当天新增用户数
            Long userCount = collect.get(date.toString());
            userCount = userCount == null ? 0 : userCount;
            newUserList.add(userCount);
            //2.8截止当天用户总数
            integer += userCount.intValue();
            totalUserList.add(integer);
        }
        //3、组装UserReportVO并返回
        return UserReportVO.builder().dateList(StringUtils.join(dateList, ","))
                .newUserList(StringUtils.join(newUserList, ","))
                .totalUserList(StringUtils.join(totalUserList, ","))
                .build();
    }

    /**
     * 订单数据统计
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {
        //1、根据起始日期，得到区间内的所有日期
        List<LocalDate> dateList = getDateList(begin, end);
        //2、分组查询每日订单总数，放入到List中
        Map param = new HashMap();
        //添加开始日期
        param.put("beginDate", begin);
        //添加结束日期
        param.put("endDate", end);
        List<Map> totalOrderMapList = ordersMapper.ordersStatistics(param);
        Map<String, Long> totalOrderMap = totalOrderMapList.stream().collect(Collectors.toMap(o -> (String) o.get("date"), o -> (Long) o.get("num")));
        //3、分组查询每日有效订单数，放入到List中
        param.put("status", Orders.COMPLETED);
        List<Map> validOrderMap = ordersMapper.groupCountOrderByParams(param);

        Map<String, Long> stringLongMap = validOrderMap.stream().collect(Collectors.toMap(o -> (String) o.get("date"), o -> (Long) o.get("num")));
        List<Long> orderCountList = new ArrayList<>();
        List<Long> validOrderCountList = new ArrayList<>();
        for (LocalDate date : dateList) {
            //获得当前日期的订单总数
            Long totalOrder = totalOrderMap.get(date.toString());
            totalOrder = totalOrder == null ? 0 : totalOrder;
            orderCountList.add(totalOrder);
            //获得当前日期的有效订单数
            Long validOrder = stringLongMap.get(date.toString());
            validOrder = validOrder == null ? 0 : validOrder;
            orderCountList.add(validOrder);
        }
        //4、统计区间内订单总数、有效订单总数
        Long totalOrderCount = orderCountList.stream().mapToLong(oc -> oc).sum();
        totalOrderCount = orderCountList.stream().reduce(Long::sum).get();
        totalOrderCount = orderCountList.stream().flatMapToLong(oc -> LongStream.of(oc)).sum();
        totalOrderCount = orderCountList.stream().mapToLong(oc -> oc).summaryStatistics().getSum();

        Long validOrderCount = validOrderCountList.stream().mapToLong(oc -> oc).sum();

        //5、计算订单完成率
        Double orderCompletionRate = totalOrderCount == 0 ? 0.0 : validOrderCount.doubleValue() / totalOrderCount;


        //6、组装OrderStatisticsVO并返回
        return OrderReportVO.builder().dateList(org.apache.commons.lang3.StringUtils.join(dateList, ","))
                .orderCountList(org.apache.commons.lang3.StringUtils.join(orderCountList, ","))
                .validOrderCountList(org.apache.commons.lang3.StringUtils.join(validOrderCountList, ","))
                .totalOrderCount(totalOrderCount.intValue())
                .validOrderCount(validOrderCount.intValue())
                .orderCompletionRate(orderCompletionRate).build();
    }

    /**
     * 销售排行统计
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public SalesTop10ReportVO top10(LocalDate begin, LocalDate end) {
        //1、根据菜品或者套餐名称进行分组查询
        Map param = new HashMap();
        //添加开始日期
        param.put("beginDate", begin);
        //添加结束日期
        param.put("endDate", end);
        param.put("status", Orders.COMPLETED);
        List<GoodsSalesDTO> goodsSalesDTOList = ordersMapper.groupSumNumberByParams(param);

        //2、转换list，得到所有菜品或套餐名称
        String nameList = goodsSalesDTOList.stream().map(goods -> goods.getName()).collect(Collectors.joining(","));

        //3、转换list，得到所有菜品或套餐销量
        String numberList = goodsSalesDTOList.stream().map(goods -> goods.getNumber().toString()).collect(Collectors.joining(","));

        return SalesTop10ReportVO.builder().nameList(nameList).numberList(numberList).build();


    }

    /**
     * 根据起始日期，得到区间内的所有日期
     *
     * @param begin 开始日期
     * @param end   结束日期
     * @return 区间内的所有日期
     */
    private List<LocalDate> getDateList(LocalDate begin, LocalDate end) {
        List<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);

        while (!begin.equals(end)) {
            begin = begin.plusDays(1);
            dateList.add(begin);
        }
        return dateList;
    }
}
